﻿using System.Text.RegularExpressions;
using Matriculex.Dominio;

namespace Matriculex.UI.Helpers
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Web.Mvc;
    using System.Linq;

    /// <summary>
    /// Class to check the current action on controller
    /// </summary>
    public static class MatriculexHtmlHelper
    {
        private static readonly Dictionary<string, object> selectedHtmlAttributes = new Dictionary<string, object>
                                                                                   {
                                                                                       { "class", "selected" }
                                                                                   };

        private const string PublicFormatLink = "<li>{0}</li>";
        private const string PrivateFormatLink = "<li class=\"private\">{0}</li>";

        #region "Public"

        public static string MatriculexActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName)
        {
            return MatriculexActionLink(helper, linkText, actionName, controllerName, PublicFormatLink);
        }

        /// <summary>
        /// Cria um ActionLink que pode estar marcado como "selected" se o controller especificado
        /// for o corrente
        /// </summary>
        /// <param name="helper">the helper instance</param>
        /// <param name="linkText">o texto que será exibido</param>
        /// <param name="controllerName">o controller do ActionLink</param>
        /// <returns></returns>
        public static string MatriculexActionLink(this HtmlHelper helper, string linkText, string controllerName)
        {
            return MatriculexActionLink(helper, linkText, new string[0], controllerName);
        }

        /// <summary>
        /// Cria um ActionLink que pode estar marcado como "selected" se algum dos controllers passado for o corrente.
        /// O link que o ActionLink aponta corresponde ao do mainController especificado.
        /// </summary>
        /// <param name="helper">the helper instance</param>
        /// <param name="linkText">o texto que será exibido</param>
        /// <param name="controllersName">a lista de controllers desejados</param>
        /// <param name="mainController">o controller do ActionLink</param>
        /// <returns></returns>
        public static string MatriculexActionLink(this HtmlHelper helper, string linkText, string[] controllersName, string mainController)
        {
            return MatriculexActionLink(helper, linkText, controllersName, mainController, PublicFormatLink);
        }

        #endregion "Public"

        #region "Private"

        public static string MatriculexActionLink<T>(this HtmlHelper helper, string linkText, string actionName, string controllerName)
            where T : class
        {
            var user = helper.ViewContext.CurrentUser<T>();
            if (user == null) return String.Empty;

            return MatriculexActionLink(helper, linkText, actionName, controllerName, PrivateFormatLink);
        }

        public static string MatriculexActionLink<T>(this HtmlHelper helper, string linkText, string controllerName)
            where T : Usuario
        {
            return MatriculexActionLink<T>(helper, linkText, new string[0], controllerName);
        }

        public static string MatriculexActionLink<T>(this HtmlHelper helper, string linkText, string[] controllersName, string mainController)
            where T : Usuario
        {
            var user = helper.ViewContext.CurrentUser<T>();
            if (user == null) return String.Empty;

            return MatriculexActionLink(helper, linkText, controllersName, mainController, PrivateFormatLink);
        }

        #endregion "Private"

        private static string MatriculexActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, string template)
        {
            Dictionary<string, object> htmlAttributes = null;

            if (helper.IsCurrentAction(actionName, controllerName))
            {
                htmlAttributes = selectedHtmlAttributes;
            }

            var link = SimpleActionLink(helper, linkText, actionName, controllerName, htmlAttributes);
            return String.Format(template, link);
        }

        private static string MatriculexActionLink(this HtmlHelper helper, string linkText, string[] controllersName, string mainController, string template)
        {
            if (String.IsNullOrEmpty(mainController))
                throw new ArgumentNullException("mainController");

            Dictionary<string, object> htmlAttributes = null;

            if (helper.IsCurrentController(mainController))
            {
                htmlAttributes = selectedHtmlAttributes;
            }

            if (htmlAttributes == null && controllersName.Length > 0)
            {
                foreach (var controllerName in controllersName)
                {
                    if (!helper.IsCurrentController(controllerName)) continue;

                    htmlAttributes = selectedHtmlAttributes;
                    break;
                }
            }

            var link = SimpleActionLink(helper, linkText, "Index", mainController, htmlAttributes);
            return String.Format(template, link);
        }

        private static string SimpleActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, Dictionary<string, object> htmlAttributes)
        {
            return HtmlHelper.GenerateLink(
                        helper.ViewContext.RequestContext,
                        helper.RouteCollection,
                        linkText,
                        null, // routeName
                        actionName,
                        controllerName,
                        null, // routerValues
                        htmlAttributes);
        }

        public static string CustomCheckBox(this HtmlHelper helper, string name, bool isChecked, object value)
        {
            return string.Format("<input type=\"checkbox\" name=\"{0}\" id=\"{0}\" value=\"{1}\" {2}/>",
                                 name, value, isChecked ? "checked=\"checked\"" : String.Empty);
        }

        public static string CustomCheckBox(this HtmlHelper helper, string name, bool isChecked, bool disabled, object value)
        {
            return string.Format("<input type=\"checkbox\" name=\"{0}\" id=\"{0}\" value=\"{1}\" {2} {3}/>",
                                 name, value, isChecked ? "checked=\"checked\"" : String.Empty,
                                 disabled? "disabled=\"disabled\"" : String.Empty);
        }

        public static string CustomCheckBox(this HtmlHelper helper, string name, bool isChecked, bool disabled, object value, Dictionary<string, string> atributos)
        {
            StringBuilder blder = new StringBuilder();
            blder.AppendFormat("<input type=\"checkbox\" name=\"{0}\" id=\"{0}\" value=\"{1}\" {2} {3}",
                                 name, value, isChecked ? "checked=\"checked\"" : String.Empty,
                                 disabled ? "disabled=\"disabled\"" : String.Empty);
            foreach (var item in atributos)
            {
                blder.AppendFormat(" {0}=\"{1}\"", item.Key, item.Value);
            }
            return blder.Append(">").ToString();
        }

        /// <summary>
        /// Cria um dropdown com valores de "começo" a "fim", com passo 1. Pode-se ser usado
        /// para criar dropdowns de anos ou dias.
        /// </summary>
        /// <param name="começo">o primeiro item do dropdown</param>
        /// <param name="fim">o último item do dropdown</param>
        /// <returns></returns>
        public static string DropdownIntervalo(this HtmlHelper helper, string id, int começo, int fim)
        {
            return DropdownIntervalo(id, começo, fim, começo);
        }

        /// <summary>
        /// Cria um dropdown com valores de "começo" a "fim", com passo 1. Pode-se ser usado
        /// para criar dropdowns de anos ou dias.
        /// </summary>
        /// <param name="começo">o primeiro item do dropdown</param>
        /// <param name="fim">o último item do dropdown</param>
        /// <param name="selecionado">qual valor deve estar previamente selecionado</param>
        /// <returns></returns>
        public static string DropdownIntervalo(this HtmlHelper helper, string id, int começo, int fim, int selecionado)
        {
            return DropdownIntervalo(id, começo, fim, selecionado);
        }

        public static string DropdownIntervalo(string id, int começo, int fim)
        {
            return DropdownIntervalo(id, começo, fim, começo);
        }

        public static string DropdownIntervalo(string id, int começo, int fim, int selecionado)
        {
            if (fim < começo)
                throw new ArgumentOutOfRangeException();
            if (selecionado > fim || selecionado < começo)
                throw new ArgumentOutOfRangeException();

            StringBuilder blder = new StringBuilder();
            blder.AppendFormat("<select name=\"{0}\" id=\"{0}\">", id);
            blder.AppendLine();
            for (int i = começo; i <= fim; i++)
            {
                if(i == selecionado)
                    blder.AppendFormat("\t<option value=\"{0}\" selected=\"selected\">{0}</option>", i);
                else
                blder.AppendFormat("\t<option value=\"{0}\">{0}</option>", i);
                blder.AppendLine();
            }
            blder.Append("</select>");
            return blder.ToString();
        }


        /// <summary>
        /// Cria um dropdown com todos os meses do ano, e atribui a cada um deles o valor numérico
        /// do mês (e.g. janeiro corresponde a 1, dezembro a 12)
        /// </summary>
        /// <param name="id">o id do dropdown</param>
        /// <returns></returns>
        public static string DropdownMes(this HtmlHelper helper, string id)
        {
            return DropdownMes(id);
        }

        public static string DropdownMes(string id)
        {
            StringBuilder blder = new StringBuilder();
            blder.AppendLine("<select name=\"" + id + "\" id=\"" + id + "\">");
            blder.AppendLine("\t<option value=\"1\" selected=\"selected\">Janeiro</option>");
            blder.AppendLine("\t<option value=\"2\">Fevereiro</option>");
            blder.AppendLine("\t<option value=\"3\">Março</option>");
            blder.AppendLine("\t<option value=\"4\">Abril</option>");
            blder.AppendLine("\t<option value=\"5\">Maio</option>");
            blder.AppendLine("\t<option value=\"6\">Junho</option>");
            blder.AppendLine("\t<option value=\"7\">Julho</option>");
            blder.AppendLine("\t<option value=\"8\">Agosto</option>");
            blder.AppendLine("\t<option value=\"9\">Setembro</option>");
            blder.AppendLine("\t<option value=\"10\">Outubro</option>");
            blder.AppendLine("\t<option value=\"11\">Novembro</option>");
            blder.AppendLine("\t<option value=\"12\">Dezembro</option>");
            blder.AppendLine("</select>");
            return blder.ToString();
        }

        /// <summary>
        /// Cria três dropdowns para dia, mês e ano, junto com labels para cada um deles.
        /// O dia é representado de 1 a 31; o mês, por extenso de Janeiro a Dezembro;
        /// o ano é escolhido pelo usuário. Os ids das dropdowns são da forma idBase_dia, idBase_mes e idBase_ano.
        /// </summary>
        /// <param name="idBase">o prefixo do id de cada dropdown</param>
        /// <returns></returns>
        public static string DropdownsData(this HtmlHelper helper, string idBase, int anoComeço, int anoFim)
        {
            StringBuilder b = new StringBuilder();
            b.AppendLine("<div class=\"form-field\">");
            // dia
            b.AppendLine("<div class=\"ipt\">");
            b.AppendLine(String.Format("<div class=\"form-label\"><label for=\"{0}\">Dia</label></div>", idBase+"dia"));
            b.AppendLine("<div class=\"form-field\">");
            b.AppendLine(helper.DropdownIntervalo(idBase+"dia", 1, 31));
            b.AppendLine("</div></div>");
            // mês
            b.AppendLine("<div class=\"ipt\">");
            b.AppendLine(String.Format("<div class=\"form-label\"><label for=\"{0}\">Mês</label></div>", idBase + "mês"));
            b.AppendLine("<div class=\"form-field\">");
            b.AppendLine(helper.DropdownMes(idBase + "mes"));
            b.AppendLine("</div></div>");
            // ano
            b.AppendLine("<div class=\"ipt\">");
            b.AppendLine(String.Format("<div class=\"form-label\"><label for=\"{0}\">Ano</label></div>", idBase + "ano"));
            b.AppendLine("<div class=\"form-field\">");
            b.AppendLine(helper.DropdownIntervalo(idBase + "ano", anoComeço, anoFim));
            b.AppendLine("</div></div>");
            // fecha o div
            b.AppendLine("</div>");

            return b.ToString();
        }

        /// <summary>
        /// Cria três dropdowns para dia, mês e ano, junto com labels para cada um deles.
        /// O dia é representado de 1 a 31; o mês, por extenso de Janeiro a Dezembro;
        /// o ano é escolhido pelo usuário. Os ids das dropdowns são da forma idBase_dia, idBase_mes e idBase_ano.
        /// </summary>
        /// <param name="idBase">o prefixo do id de cada dropdown</param>
        /// <returns></returns>
        public static string DropdownsData(this HtmlHelper helper, string idBase, int anoComeço, int anoFim, int anoSelecionado)
        {
            StringBuilder b = new StringBuilder();
            b.AppendLine("<div class=\"form-field\">");
            // dia
            b.AppendLine("<div class=\"ipt\">");
            b.AppendLine(String.Format("<div class=\"form-label\"><label for=\"{0}\">Dia</label></div>", idBase + "dia"));
            b.AppendLine("<div class=\"form-field\">");
            b.AppendLine(helper.DropdownIntervalo(idBase + "dia", 1, 31));
            b.AppendLine("</div></div>");
            // mês
            b.AppendLine("<div class=\"ipt\">");
            b.AppendLine(String.Format("<div class=\"form-label\"><label for=\"{0}\">Mês</label></div>", idBase + "mês"));
            b.AppendLine("<div class=\"form-field\">");
            b.AppendLine(helper.DropdownMes(idBase + "mes"));
            b.AppendLine("</div></div>");
            // ano
            b.AppendLine("<div class=\"ipt\">");
            b.AppendLine(String.Format("<div class=\"form-label\"><label for=\"{0}\">Ano</label></div>", idBase + "ano"));
            b.AppendLine("<div class=\"form-field\">");
            b.AppendLine(helper.DropdownIntervalo(idBase + "ano", anoComeço, anoFim, anoSelecionado));
            b.AppendLine("</div></div>");
            // fecha o div
            b.AppendLine("</div>");

            return b.ToString();
        }
    }
}
